using System;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Input;

namespace Nyanimals
{
	public class CPlayer : CAnimatedObject
	{
		Vector2 curLeftStick;
		Vector2 curRightStick;
		
		Vector3 moveVec;
		Vector2 rotatVec; // for camera
		
		// players state machine
		CObjectStateMachine stateMachine;
		
		// player collision things
        CollisionSphere boundingSphere;
		CollisionSphere pickupSphere;	
        CollisionSphere whistleSphere; // debugging purposes only
		CMovingObject heldObject;
        
        
        public CollisionSphere BoundingSphere
        {
            get { return boundingSphere;}
        }
        
        public CollisionSphere WhistleSphere
        {
            get { return whistleSphere;}
        }
        
        public void WhistleSphereUpdate()
        {
            whistleSphere.Position = Position;
        }
        
        public CMovingObject HeldObject
        {
            get { return heldObject;}
            set { heldObject = value;}
        }
		
		public Vector2 LeftStick
		{
			get { return curLeftStick;}
			set { curLeftStick = value;}
		}
		
		public Vector2 RightStick
		{
			get { return curRightStick;}
			set { curRightStick = value;}
		}
		
		public CObjectStateMachine StateMachine
		{
			get { return stateMachine;}
		}
		
		public CPlayer() : base()
		{
			Vector2 prevLeftStick = Vector2.Zero;
			Vector2 prevRightStick = Vector2.Zero;
			Vector2 curLeftStick = Vector2.Zero;
			Vector2 curRightStick = Vector2.Zero;
			position = Vector3.One;
			speed = 10.0f;
			moveVec = new Vector3(0.0f);
			rotatVec = new Vector2(0.0f);
			
            boundingSphere = new CollisionSphere(position, 1.0f);
			pickupSphere = new CollisionSphere(position, 1.0f);
            whistleSphere = new CollisionSphere(position, 1.5f);
            
            whistleSphere.Context.Active = false;
		}
		
		public override void Init()
		{
			// player's animations
            AddAnimation(new tFrameLimit(0, 0, true, "bind"));
            AddAnimation(new tFrameLimit(1, 45, true, "idle"));
            AddAnimation(new tFrameLimit(46, 90, false, "whistle")); // prev: eat
            AddAnimation(new tFrameLimit(91, 120, true, "walk"));
            AddAnimation(new tFrameLimit(121, 180, false, "jump"));
            AddAnimation(new tFrameLimit(181, 195, false, "hit"));
            AddAnimation(new tFrameLimit(196, 216, false, "pickup")); // prev: lightAttack_1
            AddAnimation(new tFrameLimit(217, 234, false, "lightAttack_2"));
            AddAnimation(new tFrameLimit(235, 264, false, "lightAttack_3"));
            AddAnimation(new tFrameLimit(286, 340, false, "death"));
            AddAnimation(new tFrameLimit(341, 412, false, "heavyAttack"));
            AddAnimation(new tFrameLimit(428, 487, false, "jumpAttack"));
            AddAnimation(new tFrameLimit(488, 532, true, "carryidle")); // prev: crash_idle
            AddAnimation(new tFrameLimit(533, 593, true, "carrywalk")); // prev: crash_walk
			AddAnimation(new tFrameLimit(594, 661, false,"PullReaction"));			
            AddAnimation(new tFrameLimit(662, 708, false, "SugarRush"));
            AddAnimation(new tFrameLimit(711, 730, false, "dash"));
            AddAnimation(new tFrameLimit(731, 760, true, "stuck"));
            
			// create stateMachine and states
			stateMachine = new CObjectStateMachine((CBaseObject)this);
			stateMachine.CreateState(new CPlayerIdleState("idle", this));
			stateMachine.CreateState(new CPlayerWalkState("walk", this));
			stateMachine.CreateState(new CPlayerCarryIdleState("carryidle", this));
			stateMachine.CreateState(new CPlayerCarryWalkState("carrywalk", this));
			stateMachine.CreateState(new CPlayerPickupState("pickup", this));
            stateMachine.CreateState(new CPlayerWhistleState("whistle", this));
			
			// start in players idle
			stateMachine.ChangeState("idle");
        }
        public override void Shutdown()
        {
        }
        
        public override Vector3 Position
        {
            get 
            {
                position = WorldMatrix.AxisW;
                return position;
            }
            set 
            {
                Matrix4 tempWorld = context.WorldMatrix;
                Pivot = position = tempWorld.AxisW = boundingSphere.Position = value;
                Context.WorldMatrix = tempWorld;
            }
        }
		
		public override ObjectTypes Type
		{
			get { return ObjectTypes.Player_Object;}
		}
		
		public override void Input()
		{
			CInput input = CInput.Instance;
			
			// get cur stick location
			curLeftStick = input.LeftAnalog;
			curRightStick = input.RightAnalog;
			
			// for device compatibility with movement
			if(input.ButtonHeld(GamePadButtons.Up))
			{
				curLeftStick.Y = -1.0f;
			}						
			if(input.ButtonHeld(GamePadButtons.Down))
			{
				curLeftStick.Y = 1.0f;
			}
			if(input.ButtonHeld(GamePadButtons.Left))
			{
				curLeftStick.X = -1.0f;
			}
						
			if(input.ButtonHeld(GamePadButtons.Right))
			{
				curLeftStick.X = 1.0f;
			}
            
            if(input.ButtonPressed(GamePadButtons.R))
            {
                CEventManager.Instance.QueueEvent(new CShowStatEvent(true));
            }
            if(input.ButtonReleased(GamePadButtons.R))
            {
                CEventManager.Instance.QueueEvent(new CShowStatEvent(false));
            }
            
			stateMachine.Input();
				
		}
        
		public override void Update(float deltaTime)
		{	
			stateMachine.Update(deltaTime);
			
			if(curLeftStick != Vector2.Zero)
			{
				LookAt(localMatrix.AxisW - velocity, Vector3.UnitY);
				TranslateLocalZ(speed * deltaTime);
			}
			
			base.Update(deltaTime);
			
			// move the pickup sphere in front of the player
			pickupSphere.Position = Position + (WorldMatrix.AxisZ * 1.25f);// + (WorldMatrix.AxisY * 1.0f);
            boundingSphere.Position = Position;
            
            
        }
        
        
		
		public override bool HandleCollision(ref CBaseObject Obj)
		{
            CObjectBaseState state = stateMachine.CurState;
			switch (Obj.Type)
			{
				case ObjectTypes.Nyanimal_Object:
				{                
                    CNyanimal nyan = (CNyanimal)Obj;
                    CollisionSphere nyanSphere = nyan.BoundingSphere;
                
                    // if we are picking up
                    if(state.StateName == "pickup")
                    {
                        // check the spheres collision
                        if(CMath.SphereToSphere(pickupSphere, nyanSphere))
                        {
    						CPlayerPickupState pickState = (CPlayerPickupState)state;
                            if(pickState.PickUp(ref nyan))
                            {
                                // Console.WriteLine("Picked up!");
                            
                                // switch states
                                stateMachine.ChangeState("carryidle");
                                nyan.StateMachine.ChangeState("hold");
                            
                                heldObject = nyan;
                                nyan.Held = true;
                            
                                // tell the display what object we are holding
                                CEventManager.Instance.QueueEvent(new CPickupObjectEvent(heldObject));
                            }
    					}
                    }
					
				} break;
            case ObjectTypes.Food_Object:
            {
                CBaseFood food = (CBaseFood)Obj;
                CollisionSphere foodBounds = food.BoundingSphere;
                
                // if we are picking up
                if(state.StateName == "pickup")
                {
                    // check the spheres collision
                    if(CMath.SphereToSphere(pickupSphere, foodBounds))
                    {
                        CPlayerPickupState pickState = (CPlayerPickupState)state;
                        if(pickState.PickUp(ref food))
                        {
                            // Console.WriteLine("Picked up!");
                        
                            // switch states
                            stateMachine.ChangeState("carryidle");
                            food.ObjectHolding = this;                        
                            heldObject = food;
                            
                            // tell the display what object we are holding
                            CEventManager.Instance.QueueEvent(new CPickupObjectEvent(heldObject));
                        }
                    }
                }
                
            } break;
            case ObjectTypes.Selectable_Object:
            {
                // TODO: handle more than 1 type of selectable
                CFoodBin bin = (CFoodBin)Obj;
                
                bool collides = CMath.SphereToBox(pickupSphere, (CollisionBox)bin.Collision);
                if(collides)
                {
                    Console.WriteLine("In Box!");
                }
            } break;
			};
			return false;
		}
	}
}


